<template>
  <div id="pageTable">
    <slot name="search"></slot>
    <el-table
      ref="elTable"
      :class="className"
      v-loading="loading"
      :row-key="rowKey"
      :data="tableData"
      :max-height="maxHeight"
      :border="border"
      :stripe="stripe"
      :tooltip-effect="tooltipEffect"
      :highlight-current-row="highlightCurrentRow"
      @select="handleSelect"
      @select-all="handleSelectAll"
      @selection-change="handleSelectionChange"
      @cell-mouse-enter="cellMouseEnter"
      @cell-mouse-leave="cellMouseLeave"
      @cell-click="cellClick"
      @cell-dblclick="cellDblclick"
      @row-click="rowClick"
      @row-contextmenu="rowContextmenu"
      @row-dblclick="rowDblclick"
      @header-click="headerClick"
      @header-contextmenu="headerContextmenu"
      @sort-change="sortChange"
      @filter-change="filterChange"
      @current-change="currentChange"
      @header-dragend="headerDragend"
      @expand-change="expandChange"
    >
      <template v-for="(item, index) in columns">
        <template v-if="item.type">
          <el-table-column
            :key="index"
            :type="item.type"
            :index="item.index"
            :label="item.label"
            :align="item.align"
            :width="item.width"
            :fixed="item.fixed"
            :reserve-selection="item.reserveSelection"
          ></el-table-column>
        </template>
        <template v-else>
          <el-table-column
            v-if="!item.formatter"
            :key="index"
            :column-key="item.columnKey"
            :label="item.label"
            :prop="item.prop"
            :width="item.width"
            :min-width="item.minWidth"
            :fixed="item.fixed"
            :render-header="item.renderHeader"
            :align="item.align"
            :show-overflow-tooltip="item.showOverflowTooltip"
            filter-placement="bottom-end"
          >
            <template slot-scope="scope">
              <slot
                :scope="scope.row"
                v-if="item.slot"
                :name="item.slot"
                :row="scope.row[item.slot]"
              />
              <ex-slot v-else-if="item.render" :render="item.render" :row="scope.row" :index="scope.$index" :column="item" />
              <span v-else>{{ scope.row[item.prop] }}</span>
            </template>
          </el-table-column>
          <el-table-column
            v-else
            :key="index"
            :column-key="item.columnKey"
            :label="item.label"
            :prop="item.prop"
            :width="item.width"
            :min-width="item.minWidth"
            :fixed="item.fixed"
            :render-header="item.renderHeader"
            :align="item.align"
            :show-overflow-tooltip="item.showOverflowTooltip"
            :formatter="item.formatter"
            filter-placement="bottom-end"
          >
          </el-table-column>
        </template>
      </template>
    </el-table>
    <pagination
      v-show="total"
      :total="total"
      :page.sync="pageNo"
      :limit.sync="limit"
      @pagination="getData"
    />
  </div>
</template>

<script>
  import { handleTree } from "@/utils/util"
  // 自定义内容的组件
  var exSlot = {
    functional: true,
    props: {
      row: Object,
      render: Function,
      index: Number,
      column: {
        type: Object,
        default: null
      }
    },
    render: (h, data) => {
      const params = {
        row: data.props.row,
        index: data.props.index
      }
      if (data.props.column) params.column = data.props.column
      return data.props.render(h, params)
    }
  }
  export default {
    name: "pageTable",
    props: {
      className: String, // 多选框改为单选框
      columns: {
        type: Array,
        required: true,
        validator: (cols) => {
          return cols.length >= 1 //表格至少需要1列
        }
      },
      params: Object,
      data: {
        type: Array,
        default: () => {
          return []
        },
      },
      url: {
        type: String,
        default: '',
      },
      border: {
        type: Boolean,
        default: true
      },
      stripe: {
        type: Boolean,
        default: true
      },
      highlightCurrentRow: {
        type: Boolean,
        default: false
      },
      tooltipEffect: {
        type: String,
        default: 'dark',
      },
      maxHeight: {
        type: Number,
        default: 1000
      },
      ispage: {
        type: Boolean,
        default: true
      },
      treeConfig: {
        type: Object,
        default: () => {
          return {
            isTree: false, id: 'id', parentId: 'parentId'
          }
        }
      },
      rowKey: {
        type: String,
        default: 'id',
      },
    },
    components: {  exSlot },
    data() {
      return {
        loading: false,
        tableData: [], // 表格数据
        total: 0, // 总条数
        pageNo: 1,
        limit: 10
      }
    },
    mounted() {
      if(this.data.length){
        this.tableData = this.data
      }
    },
    watch: {
      data(newName,oldName){
          this.tableData=newName
      }
    },

    methods: {
      // 请求数据
      getData() {
        let params = {}
        this.loading = true
        if(this.data.length){
          this.loading = false
          this.$emit('on-success', this.data)
          return false
        }
        if(!this.ispage){
          // 不分页
          params = {
            ...this.params
          }
        } else {
          params = {
            ...this.params,
            limit: this.limit,
            page: this.pageNo
          }
        }
        this.$http.get(this.url, params, this)
          .then((res) => {
            if(!this.ispage){
              // 不分页
              if(this.treeConfig.isTree){
                // 树形数据
                this.tableData = handleTree(res.data, this.treeConfig.id, this.treeConfig.parentId, 'children')
              } else {
                this.tableData = res.data
              }
            } else {
              // 总记录
              this.total = parseInt(res.data.total)
              if(this.treeConfig.isTree){
                // 树形数据  分页前端组树会有问题 待优化
                this.tableData = handleTree(res.data.records, this.treeConfig.id, this.treeConfig.parentId, 'children')
              } else {
                this.tableData = res.data.records
              }
            }
            // 执行自定义回调
            this.$emit('on-success', res.data)
          })
          .finally(() => {
            this.loading = false
          })
      },
      // 查询
      search() {
        this.pageNo = 1
        this.getData()
      },
      // 重新加载
      reload() {
        this.getData()
      },
      /**Table Events**/
      // 当用户手动勾选数据行的 Checkbox 时触发的事件
      handleSelect(selection, row){
        this.$emit('select', selection, row)
      },
      // 当选择项发生变化时会触发该事件
      handleSelectAll(selection){
        this.$emit('select-all', selection)
      },
      // 当选择项发生变化时会触发该事件
      handleSelectionChange(selection) {
        if(this.className && selection.length > 1){
          // 单选
          this.$refs.elTable.clearSelection()
          this.$refs.elTable.toggleRowSelection(selection.pop())
        }
        this.$emit('selection-change', selection)
      },
      // 当单元格 hover 进入时会触发该事件
      cellMouseEnter(row, column, cell, event){
        this.$emit('cell-mouse-enter', row, column, cell, event)
      },
      // 当单元格 hover 退出时会触发该事件
      cellMouseLeave(row, column, cell, event){
        this.$emit('cell-mouse-leave', row, column, cell, event)
      },
      // 当某个单元格被点击时会触发该事件
      cellClick(row, column, cell, event){
        this.$emit('cell-click', row, column, cell, event)
      },
      // 当某个单元格被双击击时会触发该事件
      cellDblclick(row, column, cell, event){
        this.$emit('cell-dblclick', row, column, cell, event)
      },
      // 当某一行被点击时会触发该事件
      rowClick(row, column, event){
        this.$emit('row-click', row, column, event)
      },
      // 当某一行被鼠标右键点击时会触发该事件
      rowContextmenu(row, column, event){
        this.$emit('row-contextmenu', row, column, event)
      },
      // 当某一行被双击时会触发该事件
      rowDblclick(row, column, event){
        this.$emit('row-dblclick', row, column, event)
      },
      // 当某一列的表头被点击时会触发该事件
      headerClick(column, event){
        this.$emit('header-click', column, event)
      },
      // 当某一列的表头被鼠标右键点击时触发该事件
      headerContextmenu(column, event){
        this.$emit('header-contextmenu', column, event)
      },
      // 当表格的排序条件发生变化的时候会触发该事件	{ column, prop, order }
      sortChange({ column, prop, order }){
        this.$emit('sort-change', { column, prop, order })
      },
      // 当表格的筛选条件发生变化的时候会触发该事件，参数的值是一个对象，对象的 key 是 column 的 columnKey，对应的 value 为用户选择的筛选条件的数组。
      filterChange(filters){
        this.$emit('filter-change', filters)
      },
      // 当表格的当前行发生变化的时候会触发该事件，如果要高亮当前行，请打开表格的 highlight-current-row 属性
      currentChange(currentRow, oldCurrentRow){
        this.$emit('current-change', currentRow, oldCurrentRow)
      },
      // 当拖动表头改变了列的宽度的时候会触发该事件
      headerDragend(newWidth, oldWidth, column, event){
        this.$emit('header-dragend', newWidth, oldWidth, column, event)
      },
      // 当用户对某一行展开或者关闭的时候会触发该事件（展开行时，回调的第二个参数为 expandedRows；树形表格时第二参数为 expanded）
      expandChange(row, expanded){
        this.$emit('expand-change', row, expanded)
      },
      /**Table Methods**/
      // 用于多选表格，清空用户的选择
      clearSelection(){
        this.$refs.elTable.clearSelection()
      },
      // 用于多选表格，切换某一行的选中状态，如果使用了第二个参数，则是设置这一行选中与否（selected 为 true 则选中）
      toggleRowSelection(rows, selected){
        rows.forEach(row => {
          this.$refs.elTable.toggleRowSelection(this.tableData[row], selected)
        })
      },
      // 用于可展开表格与树形表格，切换某一行的展开状态，如果使用了第二个参数，则是设置这一行展开与否（expanded 为 true 则展开）
      toggleRowExpansion(rows, expanded){
        rows.forEach(row => {
          this.$refs.elTable.toggleRowExpansion(this.tableData[row], expanded)
        })
      },
      // 用于单选表格，设定某一行为选中行，如果调用时不加参数，则会取消目前高亮行的选中状态。
      setCurrentRow(row){
        this.$refs.elTable.setCurrentRow(this.tableData[row])
      },
      // 用于清空排序条件，数据会恢复成未排序的状态
      clearSort(){
        this.$refs.elTable.clearSort()
      },
      // 不传入参数时用于清空所有过滤条件，数据会恢复成未过滤的状态，也可传入由columnKey组成的数组以清除指定列的过滤条件
      clearFilter(columnKey){
        this.$refs.elTable.clearFilter(columnKey)
      },
      // 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时，可能需要调用此方法
      doLayout(){
        this.$refs.elTable.doLayout()
      },
      // 手动对 Table 进行排序。参数prop属性指定排序列，order指定排序顺序。
      sort(prop, order){
        this.$refs.elTable.sort(prop, order)
      },

    }
  }
</script>

<style>
  .single-select-table thead .el-table-column--selection .cell{
    display: none;
  }
</style>
